/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.openide.modules;
import java.text.MessageFormat;
import java.util.*;
import java.util.jar.Manifest;
import java.util.jar.Attributes;
import java.io.PrintWriter;
import java.io.StringWriter;
import org.openide.util.NbBundle;
import org.openide.loaders.DataLoader;
import org.openide.options.SystemOption;
import org.openide.TopManager;
import org.openide.filesystems.FileSystem;
import org.openide.debugger.Debugger;
import org.openide.ServiceType;
import org.openide.util.actions.SystemAction;
import org.openide.nodes.Node;
import org.openide.util.HelpCtx;
import org.openide.util.datatransfer.ExClipboard;
/** Class representing one specially-treated section in a module's manifest file.
* For example, one section may describe a single action provided by the module.
*
* @author Jaroslav Tulach
*/
public abstract class ManifestSection extends Object {
/** name of the class file, e.g. foo/Bar.class */
String name;
/** name of the class, e.g. foo.bar */
private String className;
/** instance of the class or exeception if not possible to create it */
private Object result;
/** Package private constructor to allow creation only from this package.
* @param name name of section, should be a class file, e.g. foo/Bar.class
* @param attr attributes for one section
* @throws IllegalModuleException if the name is not valid for an OpenIDE section
*/
ManifestSection (String name, Attributes attr) throws IllegalModuleException {
this.name = name;
className = ModuleDescription.createPackageName (name);
}
/** Getter for instance of this class.
* @return the insttance
* @exception Exception if there is an error
*/
Object createInstance () throws Exception {
return java.beans.Beans.instantiate (
TopManager.getDefault ().currentClassLoader (), className
);
}
/** Getter for the only installed instance.
*
* @return the insttance
* @exception Exception if there is an error
*/
synchronized Object getInstance () throws Exception {
if (result instanceof Exception) {
((Exception)result).fillInStackTrace ();
throw (Exception)result;
}
if (result == null) {
try {
result = createInstance ();
} catch (Exception ex) {
// remember the exception
result = ex;
throw ex;
} catch (Throwable ex) {
result = new ClassNotFoundException (exceptionMessage (ex));
throw (Exception) result;
}
}
return result;
}
/** Creates a description of an exception.
* @param ex exception
* @return the string representation of the exception
*/
static String exceptionMessage (Throwable ex) {
StringWriter sw = new StringWriter ();
PrintWriter w = new PrintWriter (sw);
w.println (ex.getClass ().getName ());
ex.printStackTrace (w);
w.close ();
return sw.toString ();
}
/** Abstract method of sections that invokes right method of the given
* iterator.
* @exception Exception if the section should be removed from list of section
*/
abstract void invokeIterator (Iterator it) throws Exception;
/** Parses attributes and creates its description.
* @param name name of the section
* @param attr attribues
* @return the section or null if attributes does not represent section
* @exception IllegalModuleException if the attributes are not valid
*/
static ManifestSection createSection (String name, Attributes attr) throws IllegalModuleException {
// Analyze the section
String sectionName = attr.getValue (ModuleDescription.TAG_SECTION_CLASS);
if (sectionName == null) {
// no section tag
return null;
} else if (sectionName.equalsIgnoreCase(ModuleDescription.SECTION_ACTION)) {
return new ActionSection(name, attr);
} else if (sectionName.equalsIgnoreCase(ModuleDescription.SECTION_OPTION)) {
return new OptionSection(name, attr);
} else if (sectionName.equalsIgnoreCase(ModuleDescription.SECTION_LOADER)) {
return new LoaderSection(name, attr);
} else if (sectionName.equalsIgnoreCase(ModuleDescription.SECTION_FILESYSTEM)) {
return new FileSystemSection(name, attr);
} else if (sectionName.equalsIgnoreCase(ModuleDescription.SECTION_NODE)) {
return new NodeSection(name, attr);
} else if (sectionName.equalsIgnoreCase(ModuleDescription.SECTION_SERVICE)) {
return new ServiceSection(name, attr);
} else if (sectionName.equalsIgnoreCase(ModuleDescription.SECTION_DEBUGGER)) {
return new DebuggerSection(name, attr);
} else if (sectionName.equalsIgnoreCase(ModuleDescription.SECTION_CLIPBOARD_CONVERTOR)) {
return new ClipboardConvertorSection (name, attr);
} else {
throw new IllegalModuleException
(MessageFormat.format
(NbBundle.getBundle (ManifestSection.class).getString ("EXC_IllegalModuleClass"),
new Object[] { name, sectionName }));
}
}
/** Iterator over different types of sections.
* @see ModuleDescription#forEachSection
*/
public static interface Iterator {
/** Process action section.
* @param as the section
* @exception InstantiationException if there is an error and the section should be ignored
*/
public void processAction (ActionSection as) throws InstantiationException;
/** Process option section.
* @param os the section
* @exception InstantiationException if there is an error and the section should be ignored
*/
public void processOption (OptionSection os) throws InstantiationException;
/** Process loader section.
* @param is the section
* @exception InstantiationException if there is an error and the section should be ignored
*/
public void processLoader (LoaderSection ls) throws InstantiationException;
/** Process debugger section.
* @param ds the section
* @exception InstantiationException if there is an error and the section should be ignored
*/
public void processDebugger (DebuggerSection ds) throws InstantiationException;
/** Process service section.
* @param es the section
* @exception Instantiationception if there is an error and the section should be ignored
*/
public void processService (ServiceSection es) throws InstantiationException;
/** Process file system section.
* @param fs the section
* @exception InstantiationException if there is an error and the section should be ignored
*/
public void processFileSystem (FileSystemSection fs) throws InstantiationException;
/** Process node section.
* @param es the section
* @exception InstantiationException if there is an error and the section should be ignored
*/
public void processNode (NodeSection es) throws InstantiationException;
/** Process clipboard convertor section.
* @param ccs the section
* @exception InstantiationException if there is an error and the section should be ignored
*/
public void processClipboardConvertor (ClipboardConvertorSection ccs) throws InstantiationException;
}
/** Module section for an Action.
* @see SystemAction
*/
public static final class ActionSection extends ManifestSection {
/** name of toolbar to place the action to */
private String toolbar;
/** name of menu to place the action to */
private String menu;
/** text description of key to assign to this action */
private String key;
ActionSection(String name, Attributes attrs) throws IllegalModuleException {
super(name, attrs);
}
/** Get the action object.
* @return the action
* @exception InstantiationException if the action cannot be created
*/
public SystemAction getAction () throws InstantiationException {
try {
return (SystemAction)super.getInstance ();
} catch (Exception ex) {
throw new InstantiationException (ManifestSection.exceptionMessage (ex));
}
}
/** Calls the right method in the iterator.
*/
void invokeIterator (Iterator it) throws Exception {
it.processAction (this);
}
}
/** Module section for an Option.
* @see SystemOption
*/
public static final class OptionSection extends ManifestSection {
OptionSection (String name, Attributes attrs) throws IllegalModuleException {
super(name, attrs);
}
/** Get the system option.
* @return the option
* @exception InstantiationException if the action cannot be created
*/
public SystemOption getOption () throws InstantiationException {
try {
return (SystemOption)super.getInstance ();
} catch (Exception ex) {
throw new InstantiationException (ManifestSection.exceptionMessage (ex));
}
}
/** Calls the right method in the iterator.
*/
void invokeIterator (Iterator it) throws Exception {
it.processOption (this);
}
}
/** Module section for a Data Loader.
* @see DataLoader
*/
public static final class LoaderSection extends ManifestSection {
/** class name(s) of data object to
* be inserted after loader that recognizes its
*/
private String[] installAfter;
/** class name(s) of data object to be inserted before its recognizing
* data loader
*/
private String[] installBefore;
LoaderSection (String name, Attributes attrs) throws IllegalModuleException {
super (name, attrs);
String val = attrs.getValue (ModuleDescription.TAG_INSTALL_AFTER);
StringTokenizer tok;
List res;
if (val != null) {
tok = new StringTokenizer (val, ", "); // NOI18N
res = new LinkedList ();
while (tok.hasMoreTokens ()) {
String clazz = tok.nextToken ();
if (! clazz.equals ("")) // NOI18N
res.add (clazz);
}
installAfter = (String[]) res.toArray (new String[res.size ()]);
} else {
installAfter = null;
}
val = attrs.getValue (ModuleDescription.TAG_INSTALL_BEFORE);
if (val != null) {
tok = new StringTokenizer (val, ", "); // NOI18N
res = new LinkedList ();
while (tok.hasMoreTokens ()) {
String clazz = tok.nextToken ();
if (! clazz.equals ("")) // NOI18N
res.add (clazz);
}
installBefore = (String[]) res.toArray (new String[res.size ()]);
} else {
installBefore = null;
}
}
/** Get the data loader.
* @throws InstantiationException if the loader could not be created
* @return the loader
*/
public DataLoader getLoader () throws InstantiationException {
try {
return (DataLoader)super.getInstance ();
} catch (Exception ex) {
throw new InstantiationException (ManifestSection.exceptionMessage (ex));
}
}
/** Get the representation class(es) of the loader(s) that this one should be installed after.
* @return a list of class names, or <code>null</code>
*/
public String[] getInstallAfter () {
return installAfter;
}
/** Get the representation class(es) of the loader(s) that this one should be installed before.
* @return a list of class names, or <code>null</code>
*/
public String[] getInstallBefore () {
return installBefore;
}
/** Calls the right method in the iterator.
*/
void invokeIterator (Iterator it) throws Exception {
it.processLoader (this);
}
}
/** Module section for a Debugger.
* @see Debugger
*/
public static final class DebuggerSection extends ManifestSection {
DebuggerSection (String name, Attributes attrs) throws IllegalModuleException {
super(name, attrs);
}
/** Get the debugger object.
* @return the debugger
* @throws InstantiationException if the debugger could not be created
*/
public Debugger getDebugger () throws InstantiationException {
try {
return (Debugger)super.getInstance ();
} catch (Exception ex) {
throw new InstantiationException (ManifestSection.exceptionMessage (ex));
}
}
/** Calls the right method in the iterator.
*/
void invokeIterator (Iterator it) throws Exception {
it.processDebugger (this);
}
}
/** Module section for an Service.
* @see Service
*/
public static final class ServiceSection extends ManifestSection {
/** attributes associated with this section */
private Attributes attr;
ServiceSection(String name, Attributes attrs) throws IllegalModuleException {
super(name, attrs);
this.attr = attrs;
}
// UNUSED--
/** Get the display name of the Service.
* If none was specified, a default name will be created.
*
* @return the display name
public String getName() {
String s = (String)NbBundle.getLocalizedValue (attr, ModuleDescription.TAG_SERVICE_NAME);
if (s == null) {
return MessageFormat.format (
NbBundle.getBundle (ManifestSection.class).getString ("CTL_Service_Unknown"),
new Object[] { name }
);
} else {
return s;
}
}
*/
/** Is this service default? That means should it be placed
* in front of other services?
*
* @return true if it is
*/
public boolean isDefault () {
return Boolean.valueOf (attr.getValue (ModuleDescription.TAG_SERVICE_DEFAULT)).booleanValue ();
}
/** Getter for the default instance of this service type.
* @return the service type
* @throws InstantiationException if the Service could not be created
*/
public ServiceType getServiceType () throws InstantiationException {
try {
return (ServiceType)super.getInstance ();
} catch (Exception ex) {
throw new InstantiationException (ManifestSection.exceptionMessage (ex));
}
}
/** Create a new Service of the specified type.
* @return the Service
* @throws InstantiationException if the Service could not be created
*/
public ServiceType createServiceType () throws InstantiationException {
try {
return (ServiceType)super.createInstance ();
} catch (Exception ex) {
throw new InstantiationException (ManifestSection.exceptionMessage (ex));
}
}
/** Calls the right method in the iterator.
*/
void invokeIterator (Iterator it) throws Exception {
it.processService (this);
}
}
/** Module section for a File System.
* @see FileSystem
*/
public static final class FileSystemSection extends ManifestSection {
/** attributes associated with this section */
private Attributes attr;
/** Constructor */
FileSystemSection (String name, Attributes attr) throws IllegalModuleException {
super (name, attr);
this.attr = attr;
}
/** Get the display name of the file system.
* This could be used e.g. in a context menu on the Repository.
* If none was specified, a default name will be created.
*
* @return the name
*/
public String getName() {
String s = (String)NbBundle.getLocalizedValue (attr, ModuleDescription.TAG_FILESYSTEM_NAME);
if (s == null) {
return MessageFormat.format (
NbBundle.getBundle (ManifestSection.class).getString ("CTL_Repository_Unknown"),
new Object[] { this.name }
);
} else {
return s;
}
}
/** Get a help context for the file system.
* If none was specified, a default context will be created.
* @return the help context
*/
public HelpCtx getHelpCtx () {
String s = attr.getValue (ModuleDescription.TAG_FILESYSTEM_HELP);
return s == null ?
org.openide.util.HelpCtx.DEFAULT_HELP :
// [PENDING] this constructor looks for a JavaHelp tag, but docs say /com/mycom/index.html!
new org.openide.util.HelpCtx(s);
}
/** Create a new file system.
* @return the file system
* @throws InstantiationException if it could not be created
*/
public FileSystem createFileSystem () throws InstantiationException {
try {
return (FileSystem)super.createInstance ();
} catch (Exception ex) {
if (System.getProperty("netbeans.debug.exceptions") != null) ex.printStackTrace();
throw new InstantiationException (ManifestSection.exceptionMessage (ex));
}
}
/** Calls the right method in the iterator.
*/
void invokeIterator (Iterator it) throws Exception {
it.processFileSystem (this);
}
}
/** Module section for a node.
* @see Node
*/
public static final class NodeSection extends ManifestSection {
/** Type to add an entry to the root nodes. */
public static final String TYPE_ROOTS = "roots"; // NOI18N
/** Type to add an entry to the Environment (in the Explorer). */
public static final String TYPE_ENVIRONMENT = "environment"; // NOI18N
/** Type to add an entry to the Session settings. */
public static final String TYPE_SESSION = "session"; // NOI18N
/** type of the node */
private String type;
NodeSection (String name, Attributes attrs) throws IllegalModuleException {
super(name, attrs);
type = attrs.getValue (ModuleDescription.TAG_NODE_TYPE);
}
/** Get the environment node.
* @return the node
* @exception InstantiationException if the node could not be created
*/
public Node getNode () throws InstantiationException {
try {
return (Node)super.getInstance ();
} catch (Exception ex) {
throw new InstantiationException (ManifestSection.exceptionMessage (ex));
}
}
/** Get the node type. Determines where the node should be placed in
* the IDE.
* @return one of {@link #TYPE_ROOTS}, {@link #TYPE_ENVIRONMENT}, or {@link #TYPE_SESSION}, or <code>null</code> if unspecified
*/
public String getType () {
return type;
}
/** Calls the right method in the iterator.
*/
void invokeIterator (Iterator it) throws Exception {
it.processNode (this);
}
}
/** Module section for a Clipboard convertor.
* @see ExClipboard.Convertor
*/
public static final class ClipboardConvertorSection extends ManifestSection {
ClipboardConvertorSection (String name, Attributes attrs) throws IllegalModuleException {
super(name, attrs);
}
/** Get the convertor.
* @return the convertor
* @exception InstantiationException if the object could not be created
*/
public ExClipboard.Convertor getConvertor () throws InstantiationException {
try {
return (ExClipboard.Convertor)super.getInstance ();
} catch (Exception ex) {
throw new InstantiationException (ManifestSection.exceptionMessage (ex));
}
}
/** Calls the right method in the iterator.
*/
void invokeIterator (Iterator it) throws Exception {
it.processClipboardConvertor (this);
}
}
}
/*
* Log
* 16 Gandalf 1.15 1/12/00 Ian Formanek NOI18N
* 15 Gandalf 1.14 12/8/99 Petr Hamernik compilable by Javac V8
* (jdk1.3)
* 14 Gandalf 1.13 11/25/99 Jesse Glick Rewrite of
* LoaderPoolNode, specifically the management of loader ordering. Now
* permits multiple -before and -after dependencies, and should be more
* robust. Also made LoaderPoolItemNode's properly deletable and fixed a
* timing-related NullPointerException when uninstalling modules.
* 13 Gandalf 1.12 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 12 Gandalf 1.11 10/10/99 Petr Hamernik console debug messages
* removed.
* 11 Gandalf 1.10 10/4/99 Jesse Glick Removed unused service
* type name.
* 10 Gandalf 1.9 9/10/99 Jaroslav Tulach Service section.
* 9 Gandalf 1.8 8/27/99 Jesse Glick Fixed #3590. Cleaned up
* random stuff in ManifestSection. Removed deprecated call from
* ModuleDescription test constructor.
* 8 Gandalf 1.7 6/28/99 Jaroslav Tulach Debugger types are like
* Executors
* 7 Gandalf 1.6 6/8/99 Ian Formanek ---- Package Change To
* org.openide ----
* 6 Gandalf 1.5 5/27/99 Jesse Glick [JavaDoc]
* 5 Gandalf 1.4 5/27/99 Jaroslav Tulach Executors rearanged.
* 4 Gandalf 1.3 5/11/99 Jesse Glick [JavaDoc]
* 3 Gandalf 1.2 5/7/99 Jesse Glick Module localization.
* 2 Gandalf 1.1 4/27/99 Jesse Glick new HelpCtx () ->
* HelpCtx.DEFAULT_HELP.
* 1 Gandalf 1.0 4/7/99 Ian Formanek
* $
*/